home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagn_r.zip / POINTERS.SWG / 0016_Linked List Routine.pas < prev    next >
Pascal/Delphi Source File  |  1994-05-26  |  11KB  |  388 lines

  1.  
  2. { Links Unit - Turbo Pascal 5.5
  3.   Patterned after the list processing facility in Simula class SIMSET.
  4.   Simula fans will note the same naming conventions as Simula-67.
  5.  
  6.   Written by Bill Zech @CIS:[73547,1034]), May 16, 1989.
  7.  
  8.   The Links unit defines objects and methods useful for implementing
  9.   list (set) membership in your own objects.
  10.  
  11.   Any object which inherits object <Link> will acquire the attributes
  12.   needed to maintain that object in a doubly-linked list.  Because the
  13.   Linkage object only has one set of forward and backward pointers, a
  14.   given object may belong to only one list at any given moment.  This
  15.   is sufficient for many purposes.  For example, a task control block
  16.   might belong in either a ready list, a suspended list, or a swapped
  17.   list, but all are mutually exclusive.
  18.  
  19.   A list is defined as a head node and zero or more objects linked
  20.   to the head node.  A head node with no other members is an empty
  21.   list.  Procedures and functions are provided to add members to the
  22.   end of the list, insert new members in position relative to an
  23.   existing member, determine the first member, last member, size
  24.   (cardinality) of the list, and to remove members from the list.
  25.  
  26.   Because your object inherits all these attributes, your program
  27.   need not concern itself with allocating or maintaining pointers
  28.   or other stuff.  All the actual linkage mechanisms will be
  29.   transparent to your object.
  30.  
  31.   *Note*
  32.           The following discussion assumes you have defined your objects
  33.           as static variables instead of pointers to objects.  For most
  34.           programs, dynamic objects manipulated with pointers will be
  35.           more useful.  Some methods require pointers as arguments.
  36.           Example program TLIST.PAS uses pointer type variables.
  37.  
  38.   Define your object as required, inheriting object Link:
  39.  
  40.                 type
  41.                         myObjType = object(Link)
  42.                                 xxx.....xxxx
  43.                         end;
  44.  
  45.   To establish a new list, declare a variable for the head node
  46.   as a type Head:
  47.  
  48.                 var
  49.                         Queue1        :Head;
  50.                         Queue2        :Head;
  51.  
  52.         Define your object variables:
  53.  
  54.                 var
  55.                         X    : myObjType;
  56.                         Y    : myObjType;
  57.                         Z    : myObjType;
  58.                         P    :^myObjType;
  59.  
  60.         Make sure the objects have been Init'ed as required for data
  61.         initialization, VMT setup, etc.
  62.  
  63.                         Queue1.Init;
  64.                         Queue2.Init;
  65.                         X.Init;
  66.                         Y.Init;
  67.                         Z.Init;
  68.  
  69.         You can add your objects to a list with <Into>:
  70.         (Note the use of the @ operator to make QueueX a pointer to the
  71.          object.)
  72.  
  73.                 begin
  74.                         X.Into(@Queue1);
  75.                         Y.Into(@Queue2);
  76.  
  77.         You can insert at a specific place with <Precede> or <Follow>:
  78.  
  79.                         Z.Precede(@Y);
  80.                         Z.Follow(@Y);
  81.  
  82.         Remove an object with <Out>:
  83.  
  84.                         Y.Out;
  85.  
  86.         Then add it to another list:
  87.  
  88.                         Y.Into(@Queue1);
  89.  
  90.         Note that <Into>, <Precede> and <Follow> all have a built-in
  91.         call to Out, so to move an object from one list to another can
  92.         be had with a single operation:
  93.  
  94.                         Z.Into(@Queue1);
  95.  
  96.         You can determine the first and last elements with <First> and <Last>:
  97.         (Note the functions return pointers to objects.)
  98.  
  99.                         P := Queue1.First;
  100.                         P := Queue1.Last;
  101.  
  102.         The succcessor or predecessor of a given member can be found with
  103.         fucntions <Suc> and <Pred>:
  104.  
  105.                         P := X.Pred;
  106.                         P := Y.Suc;
  107.                         P := P^.Suc;
  108.  
  109.         The number of elements in a list is found with <Cardinal>:
  110.  
  111.                         N := Queue1.Cardinal;
  112.  
  113.         <Empty> returns TRUE is the list has no members:
  114.  
  115.                         if Queue1.Empty then ...
  116.  
  117.         You can remove all members from a list with <Clear>:
  118.  
  119.                         Queue1.Clear;
  120.  
  121.         GENERAL NOTES:
  122.  
  123.                 The TP 5.5 type compatibility rules allow a pointer to a
  124.                 descendant be assigned to an ancestor pointer, but not vice-versa.
  125.                 So although it is perfectly legal to assign a pointer to
  126.                 type myObjType to a pointer to type Linkage, it won't let
  127.                 us do it the opposite.
  128.  
  129.                 We would like to be able to assign returned values from
  130.                 Suc, Pred, First, and Last to pointers of type myObjType,
  131.                 and the least fussy way is to define these pointer types
  132.                 internal to this unit as untyped pointers.  This works fine
  133.                 because all we are really doing is passing around pointers
  134.                 to Self, anyway.  The only down-side to this I have noticed
  135.                 is you can't do:  P^.Suc^.Pred because the returned pointer
  136.                 type cannot be dereferenced without a type cast.
  137. }
  138.  
  139. unit Links;
  140.  
  141. interface
  142.  
  143. type
  144.  
  145.   pLinkage = ^Linkage;
  146.   pLink = ^Link;
  147.   pHead = ^Head;
  148.  
  149.   Linkage = object
  150.           prede :pLinkage;
  151.           succ  :pLinkage;
  152.           function Suc  :pointer;
  153.           function Pred :pointer;
  154.           constructor Init;
  155.   end;
  156.  
  157.   Link = object(Linkage)
  158.           procedure Out;
  159.           procedure Into(s :pHead);
  160.           procedure Follow (x :pLinkage);
  161.           procedure Precede(x :pLinkage);
  162.   end;
  163.  
  164.   Head = object(Linkage)
  165.           function First :pointer;
  166.           function Last  :pointer;
  167.           function Empty :boolean;
  168.           function Cardinal :integer;
  169.           procedure Clear;
  170.           constructor Init;
  171.   end;
  172.  
  173.  
  174.  
  175. implementation
  176.  
  177. constructor Linkage.Init;
  178. begin
  179.   succ := NIL;
  180.   prede := NIL;
  181. end;
  182.  
  183. function Linkage.Suc :pointer;
  184. begin
  185.   if TypeOf(succ^) = TypeOf(Head) then
  186.          Suc := NIL
  187.   else Suc := succ;
  188. end;
  189.  
  190. function Linkage.Pred :pointer;
  191. begin
  192.   if TypeOf(prede^) = TypeOf(Head) then
  193.          Pred := NIL
  194.   else Pred := prede;
  195. end;
  196.  
  197. procedure Link.Out;
  198. begin
  199.         if succ <> NIL then
  200.         begin
  201.           succ^.prede := prede;
  202.           prede^.succ := succ;
  203.           succ := NIL;
  204.           prede := NIL;
  205.         end;
  206. end;
  207.  
  208. procedure Link.Follow(x :pLinkage);
  209. begin
  210.         Out;
  211.         if x <> NIL then
  212.         begin
  213.           if x^.succ <> NIL then
  214.           begin
  215.                   prede := x;
  216.                   succ := x^.succ;
  217.                   x^.succ := @Self;
  218.                   succ^.prede := @Self;
  219.           end;
  220.         end;
  221. end;
  222.  
  223.  
  224. procedure Link.Precede(x :pLinkage);
  225. begin
  226.         Out;
  227.         if x <> NIL then
  228.         begin
  229.                 if x^.succ <> NIL then
  230.                 begin
  231.                         succ := x;
  232.                         prede := x^.prede;
  233.                         x^.prede := @Self;
  234.                         prede^.succ := @Self;
  235.                 end;
  236.         end;
  237. end;
  238.  
  239. procedure Link.Into(s :pHead);
  240. begin
  241.         Out;
  242.         if s <> NIL then
  243.         begin
  244.                 succ := s;
  245.                 prede := s^.prede;
  246.                 s^.prede := @Self;
  247.                 prede^.succ := @Self;
  248.         end;
  249. end;
  250.  
  251.  
  252. function Head.First :pointer;
  253. begin
  254.         First := suc;
  255. end;
  256.  
  257. function Head.Last :pointer;
  258. begin
  259.         Last := Pred;
  260. end;
  261.  
  262. function Head.Empty :boolean;
  263. begin
  264.   Empty := succ = prede;
  265. end;
  266.  
  267. function Head.Cardinal :integer;
  268. var
  269.         i   :integer;
  270.         p   :pLinkage;
  271. begin
  272.         i := 0;
  273.         p := succ;
  274.         while p <> @Self do
  275.           begin
  276.                   i := i + 1;
  277.                   p := p^.succ;
  278.           end;
  279.         Cardinal := i;
  280. end;
  281.  
  282. procedure Head.Clear;
  283. var
  284.         x  : pLink;
  285. begin
  286.         x := First;
  287.         while x <> NIL do
  288.           begin
  289.                   x^.Out;
  290.                   x := First;
  291.           end;
  292. end;
  293.  
  294. constructor Head.Init;
  295. begin
  296.   succ := @Self;
  297.   prede := @Self;
  298. end;
  299.  
  300. end.
  301.  
  302. {------------------------   DEMO PROGRAM --------------------- }
  303.  
  304. program tlist;
  305.  
  306. uses Links;
  307.  
  308. type
  309.         NameType = string[10];
  310.         person = object(link)
  311.                 name :NameType;
  312.                 constructor init(nameArg :NameType);
  313.         end;
  314.         Pperson = ^person;
  315.  
  316. constructor person.init(nameArg :NameType);
  317. begin
  318.         name := nameArg;
  319.         link.init;
  320. end;
  321.  
  322. var
  323.         queue : Phead;
  324.         man   : Pperson;
  325.         man2  : Pperson;
  326.         n     : integer;
  327.         tf    : boolean;
  328.  
  329. begin
  330.         new(queue,Init);
  331.         tf := queue^.Empty;
  332.         new(man,Init('Bill'));
  333.         man^.Into(queue);
  334.         new(man,Init('Tom'));
  335.         man^.Into(queue);
  336.         new(man,Init('Jerry'));
  337.         man^.Into(queue);
  338.  
  339.         man := queue^.First;
  340.         writeln('First man in queue is ',man^.name);
  341.         man := queue^.Last;
  342.         writeln('Last man in queue is ',man^.name);
  343.  
  344.         n := queue^.Cardinal;
  345.         writeln('Length of queue is ',n);
  346.         if not queue^.Empty then writeln('EMPTY reports queue NOT empty');
  347.  
  348.         new(man2,Init('Hugo'));
  349.         man2^.Precede(man);
  350.  
  351.         new(man2,Init('Alfonso'));
  352.         man2^.Follow(man);
  353.         { should now be: Bill Tom Hugo Jerry Alfonso }
  354.         writeln('After PRECEDE and FOLLOW calls, list should be:');
  355.         writeln('  {Bill, Tom, Hugo, Jerry, Alfonso}');
  356.         writeln('Actual list is:');
  357.  
  358.         man := queue^.First;
  359.         while man <> NIL do
  360.           begin
  361.                   write(man^.name,' ');
  362.                   man := man^.Suc;
  363.           end;
  364.           writeln;
  365.  
  366.         man := queue^.Last;
  367.         writeln('The same list backwards is:');
  368.         while man <> NIL do
  369.           begin
  370.                  write(man^.name,' ');
  371.                  man := man^.Pred;
  372.           end;
  373.           writeln;
  374.  
  375.         n := queue^.Cardinal;
  376.         writeln('Queue size should be 5 now, is: ', n);
  377.  
  378.         queue^.Clear;
  379.         writeln('After clear operation,');
  380.         n := queue^.Cardinal;
  381.         writeln('   Queue size is ',n);
  382.         tf := queue^.Empty;
  383.         if tf then writeln('    and EMTPY reports queue is empty.');
  384.         writeln;
  385.         writeln('Done with test.');
  386. end.
  387.  
  388.